import {
    Controller,
    Post,
    Body,
    Get,
    Put,
    Inject,
    Query,
    HttpStatus,
    DefaultValuePipe, Param,
} from '@nestjs/common';
import {UserService} from './user.service';
import {RegisterUserDto} from './dto/register-user.dto';
import {LoginUserDto} from './dto/login-user.dto';
import {EmailService} from '../middleware/email/email.service';
import {RedisService} from '../middleware/redis/redis.service';
import {JwtService} from '@nestjs/jwt';
import {ConfigService} from '@nestjs/config';
import {UnauthorizedException} from '@nestjs/common';
import {SetMetadata} from '@nestjs/common';
import {
    RequireLogin,
    RequirePermission,
    UserInfo,
} from 'src/middleware/RBAC/custom.decorator';
import {UserDetailVo} from './vo/user-info.vo';
import {
    ApiTags,
    ApiResponse,
    ApiOperation,
    ApiQuery,
    ApiBearerAuth, ApiParam,
} from '@nestjs/swagger';
import {PublicVoSuccess, PublicVoError} from '../utils/publicVo/index';
import {LoginUserVo} from './vo/login-user.vo';
import {UpdateUserPasswordDto} from './dto/update-user-password.dto';
import {UpdateUserDto} from './dto/udpate-user.dto';
import {generateParseIntPipe} from '../utils/paging/index';
import {UserListVo} from './vo/user-list.vo';
import * as svgCaptcha from 'svg-captcha';
import {DisabledUserDto} from "./dto/disabled-user.dto";

@ApiTags('用户管理模块')
@Controller('user')
export class UserController {
    constructor(private readonly userService: UserService) {
    }

    @Inject(EmailService)
    private emailService: EmailService;

    @Inject(RedisService)
    private redisService: RedisService;

    @Inject(JwtService)
    private jwtService: JwtService;

    @Inject(ConfigService)
    private configService: ConfigService;

    // 用户注册
    @Post('register')
    @ApiOperation({summary: '用户注册', description: '用户注册接口'})
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async register(@Body() registerUser: RegisterUserDto) {
        return await this.userService.register(registerUser);
    }

    // 发送用户注册验证码
    @Get('register-captcha')
    @ApiOperation({
        summary: '发送用户注册验证码',
        description: '发送用户注册 邮件 验证码接口',
    })
    @ApiQuery({
        name: 'address',
        type: String,
        description: '邮箱地址',
        required: true,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async captcha(@Query('address') address: string) {
        const code = Math.random().toString().slice(2, 8);

        await this.redisService.set(`captcha_${address}`, code, 5 * 60);

        await this.emailService.sendMail({
            to: address,
            subject: '注册验证码',
            html: `<p>你的注册验证码是 ${code}</p>`,
        });
        return '发送成功';
    }

    // 插入初始化数据
    @Get('init-data')
    @ApiOperation({summary: '初始化数据', description: '插入初始化数据接口'})
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async initData() {
        await this.userService.initData();
        return 'done';
    }

    // 用户端登陆
    // @Post('login')
    // async userLogin(@Body() loginUser: LoginUserDto) {
    //   const vo = await this.userService.login(loginUser, false);
    //   return vo;
    // }
    // 管理端登陆
    // @Post('admin/login')
    // async adminLogin(@Body() loginUser: LoginUserDto) {
    //   const vo = await this.userService.login(loginUser, false);
    //   return vo;
    // }
    // 用户端登陆 jwt
    @Post('login')
    @ApiOperation({summary: '用户端登录', description: '用户端登陆接口'})
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: LoginUserVo,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async userLogin(@Body() loginUser: LoginUserDto) {
        const vo = await this.userService.login(loginUser, false);

        vo.accessToken = this.jwtService.sign(
            {
                userId: vo.userInfo.id,
                username: vo.userInfo.username,
                email: vo.userInfo.email,
                roles: vo.userInfo.roles,
                permissions: vo.userInfo.permissions,
            },
            {
                expiresIn:
                    this.configService.get('jwt_access_token_expires_time') || '30m',
            },
        );

        vo.refreshToken = this.jwtService.sign(
            {
                userId: vo.userInfo.id,
            },
            {
                expiresIn:
                    this.configService.get('jwt_refresh_token_expres_time') || '7d',
            },
        );

        return vo;
    }

    // 用户端刷新 token
    @Get('refresh')
    @ApiOperation({
        summary: '用户端 tonken 无感刷新',
        description: '用户端 tonken 无感刷新接口',
    })
    @ApiQuery({
        name: 'refreshToken',
        type: String,
        description: '刷新token',
        required: true,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async refresh(@Query('refreshToken') refreshToken: string) {
        try {
            const data = this.jwtService.verify(refreshToken);

            const user = await this.userService.findUserById(data.userId, false);

            const access_token = this.jwtService.sign(
                {
                    userId: user.id,
                    username: user.username,
                    email: user.email,
                    roles: user.roles,
                    permissions: user.permissions,
                },
                {
                    expiresIn:
                        this.configService.get('jwt_access_token_expires_time') || '30m',
                },
            );

            const refresh_token = this.jwtService.sign(
                {
                    userId: user.id,
                },
                {
                    expiresIn:
                        this.configService.get('jwt_refresh_token_expres_time') || '7d',
                },
            );

            return {
                access_token,
                refresh_token,
            };
        } catch (e) {
            throw new UnauthorizedException('token 已失效，请重新登录');
        }
    }

    // 管理端登陆 jwt
    @Post('admin/login')
    @ApiOperation({summary: '管理端登录', description: '管理端登陆接口'})
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: LoginUserVo,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async adminLogin(@Body() loginUser: LoginUserDto) {
        const vo = await this.userService.login(loginUser, true);

        vo.accessToken = this.jwtService.sign(
            {
                userId: vo.userInfo.id,
                username: vo.userInfo.username,
                email: vo.userInfo.email,
                roles: vo.userInfo.roles,
                permissions: vo.userInfo.permissions,
            },
            {
                expiresIn:
                    this.configService.get('jwt_access_token_expires_time') || '30m',
            },
        );

        vo.refreshToken = this.jwtService.sign(
            {
                userId: vo.userInfo.id,
            },
            {
                expiresIn:
                    this.configService.get('jwt_refresh_token_expres_time') || '7d',
            },
        );

        return vo;
    }

    // 后台管理刷新 token
    @Get('admin/refresh')
    @ApiOperation({
        summary: '管理端 tonken 无感刷新',
        description: '管理端 tonken 无感刷新接口',
    })
    @ApiQuery({
        name: 'refreshToken',
        type: String,
        description: '刷新token',
        required: true,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async adminRefresh(@Query('refreshToken') refreshToken: string) {
        try {
            const data = this.jwtService.verify(refreshToken);

            const user = await this.userService.findUserById(data.userId, true);

            const access_token = this.jwtService.sign(
                {
                    userId: user.id,
                    username: user.username,
                    email: user.email,
                    roles: user.roles,
                    permissions: user.permissions,
                },
                {
                    expiresIn:
                        this.configService.get('jwt_access_token_expires_time') || '30m',
                },
            );

            const refresh_token = this.jwtService.sign(
                {
                    userId: user.id,
                },
                {
                    expiresIn:
                        this.configService.get('jwt_refresh_token_expres_time') || '7d',
                },
            );

            return {
                access_token,
                refresh_token,
            };
        } catch (e) {
            throw new UnauthorizedException('token 已失效，请重新登录');
        }
    }

    // 图形验证码
    @Get('captcha')
    @ApiOperation({
        summary: '图形验证码',
        description: '获取登录图形验证码接口',
    })
    async getCaptcha() {
        const captcha = svgCaptcha.create({
            ignoreChars: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
            size: 4, // 验证码长度
            noise: 1, // 干扰线条数目
        });
        // 图片验证码 文字
        const text = captcha.text;
        // 图片验证码
        const svg = captcha.data;
        await this.redisService.set(`svg_captcha_${text}`, captcha.text, 1 * 60);
        return svg;
    }

    // 登录权限、角色权限
    @Get('text/login1')
    @ApiOperation({summary: '登录权限（有）', description: '登录权限接口'})
    @ApiBearerAuth()
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @SetMetadata('require-login', true)
    login1() {
        return '无登录权限';
    }

    @Get('text/login2')
    @ApiOperation({summary: '登录权限（无）', description: '登录权限接口'})
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    login2() {
        return '有登录权限';
    }

    @Get('text/permission1')
    @ApiOperation({summary: '角色权限（有）', description: '角色权限接口'})
    @ApiBearerAuth()
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @SetMetadata('require-login', true)
    @SetMetadata('require-permission', ['ccc'])
    permission1() {
        return '无角色权限';
    }

    @Get('text/permission2')
    @ApiOperation({summary: '角色权限（无）', description: '角色权限接口'})
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    permission2() {
        return '有角色权限';
    }

    @Get('text/permission3')
    @ApiOperation({summary: '封装JWT鉴权', description: '封装JWT鉴权接口'})
    @ApiBearerAuth()
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    @RequirePermission('ccc')
    permission3(@UserInfo('username') username: string, @UserInfo() userInfo) {
        console.log(username);
        console.log(userInfo);
        return '有角色权限';
    }

    // 修改用户端、管理端密码
    @Post('update_password')
    @ApiOperation({
        summary: '修改用户端密码',
        description: '修改用户端密码接口',
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    // @RequireLogin()
    async updateUserPassword(
        // @UserInfo('userId') userId: number,
        @Body() passwordDto: UpdateUserPasswordDto,
    ) {
        return await this.userService.updatePassword(passwordDto, false);
    }

    @Post('admin/update_password')
    @ApiOperation({
        summary: '修改管理端密码',
        description: '修改管理端密码接口',
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    // @RequireLogin()
    async updateAdminPassword(
        // @UserInfo('userId') userId: number,
        @Body() passwordDto: UpdateUserPasswordDto,
    ) {
        return await this.userService.updatePassword(passwordDto, true);
    }

    // 发送修改密码验证码
    @Get('update_password/captcha')
    @ApiOperation({
        summary: '发送修改密码验证码',
        description: '发送修改密码 邮件验证码接口',
    })
    @ApiQuery({
        name: 'address',
        type: String,
        description: '邮箱地址',
        required: true,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    async updatePasswordCaptcha(@Query('address') address: string) {
        const code = Math.random().toString().slice(2, 8);

        await this.redisService.set(
            `update_password_captcha_${address}`,
            code,
            10 * 60,
        );

        await this.emailService.sendMail({
            to: address,
            subject: '更改密码验证码',
            html: `<p>你的更改密码验证码是 ${code}</p>`,
        });
        return '发送成功';
    }

    // 修改用户端、管理端用户信息
    @Post(['update', 'admin/update'])
    @ApiOperation({
        summary: '修改用户端、管理端用户信息',
        description: '修改用户端、管理端用户信息接口',
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async update(
        @UserInfo('userId') userId: number,
        @Body() updateUserDto: UpdateUserDto,
    ) {
        return await this.userService.update(userId, updateUserDto);
    }

    // 发送修改用户信息验证码
    @Get('update/captcha')
    @ApiOperation({
        summary: '发送修改用户信息验证码',
        description: '发送修改用户信息 邮件验证码接口',
    })
    // @ApiQuery({
    //   name: 'address',
    //   type: String,
    //   description: '邮箱地址',
    //   required: true,
    // })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async updateCaptcha(@UserInfo('email') address: string) {
        console.log(address);
        const code = Math.random().toString().slice(2, 8);

        await this.redisService.set(
            `update_user_captcha_${address}`,
            code,
            10 * 60,
        );

        await this.emailService.sendMail({
            to: address,
            subject: '更改用户信息验证码',
            html: `<p>你的验证码是 ${code}</p>`,
        });
        return '发送成功';
    }

    // 个人信息
    @Get('info')
    @ApiOperation({summary: '个人信息', description: '个人信息无需传值接口'})
    @ApiBearerAuth()
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: UserDetailVo,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async info(@UserInfo('userId') userId: number) {
        console.log(userId, 'userId');

        const user = await this.userService.findUserDetailById(userId);

        const vo = new UserDetailVo();
        vo.id = user.id;
        vo.email = user.email;
        vo.username = user.username;
        vo.headPic = user.headPic;
        vo.phoneNumber = user.phoneNumber;
        vo.nickName = user.nickName;
        vo.createTime = user.createTime;
        vo.isFrozen = user.isFrozen;
        vo.isAdmin = user.isAdmin;

        return vo;
    }

    // 用户列表
    @Get('list')
    @ApiOperation({
        summary: '用户列表',
        description: '用户列表接口',
    })
    @ApiBearerAuth()
    @ApiQuery({
        name: 'pageNum',
        type: String,
        description: '页码',
        required: true,
    })
    @ApiQuery({
        name: 'pageSize',
        type: String,
        description: '页数',
        required: true,
    })
    @ApiQuery({
        name: 'username',
        type: String,
        description: '用户名',
        required: false,
    })
    @ApiQuery({
        name: 'nickName',
        type: String,
        description: '昵称',
        required: false,
    })
    @ApiQuery({
        name: 'email',
        type: String,
        description: '邮箱',
        required: false,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: UserListVo,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async list(
        @Query('pageNum', new DefaultValuePipe(1), generateParseIntPipe('pageNum'))
            pageNo: number,
        @Query(
            'pageSize',
            new DefaultValuePipe(0),
            generateParseIntPipe('pageSize'),
        )
            pageSize: number,
        @Query('username') username: string,
        @Query('nickName') nickName: string,
        @Query('email') email: string,
    ) {
        return await this.userService.findUsers(
            username,
            nickName,
            email,
            pageNo,
            pageSize,
        );
    }

    // 个人信息 id
    @Get('list/:id')
    @ApiOperation({summary: '用户列表详情', description: '用户列表详情接口'})
    @ApiBearerAuth()
    @ApiParam({
        name: 'id',
        type: String,
        description: '用户id',
        required: true,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: UserDetailVo,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async findInfo(@Param('id') id: string) {

        const user = await this.userService.findUserListById(Number(id));

        const vo = new UserDetailVo();
        vo.id = user.id;
        vo.email = user.email;
        vo.username = user.username;
        vo.headPic = user.headPic;
        vo.phoneNumber = user.phoneNumber;
        vo.nickName = user.nickName;
        vo.createTime = user.createTime;
        vo.isFrozen = user.isFrozen;
        vo.isAdmin = user.isAdmin;

        return vo;
    }

    // 冻结用户
    @Put('freeze')
    @ApiOperation({
        summary: '冻结用户',
        description: '冻结用户接口',
    })
    @ApiBearerAuth()
    @ApiQuery({
        name: 'id',
        type: String,
        description: '用户id',
        required: true,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async freeze(@Query('id') id: number) {
        await this.userService.freezeUserById(id);
        return 'success';
    }

    // 启用停用用户
    @Put('disabled')
    @ApiOperation({
        summary: '用户启用停用',
        description: '用户启用停用接口',
    })
    @ApiBearerAuth()

    @ApiResponse({
        status: HttpStatus.OK,
        description: '请求成功',
        type: PublicVoSuccess,
    })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '请求失败',
        type: PublicVoError,
    })
    @RequireLogin()
    async disabled(@Body() disabledUserDto: DisabledUserDto,) {
        await this.userService.disabledUse(disabledUserDto);
        return 'success';
    }


}
